package com.sniper.web.utils;

import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

import static org.quartz.CronScheduleBuilder.cronSchedule;

/**
 * http://blog.csdn.net/lnara/article/details/8634717
 *
 * @author suzhen
 */
@Component
public class QuartzManagerUtil {


    /**
     * 定义基本常量,job组名字，触发器名字
     */
    private static String JOB_GROUP_NAME = "EXT_WEB_JOB_GROUP_NAME";
    private static String TRIGGER_GROUP_NAME = "EXT_WEB_TRIGGER_GROUP_NAME";

    @Resource
    SchedulerFactoryBean springFactoryBean;

    /**
     * @return
     * @throws SchedulerException
     */
    public Scheduler getScheduler() throws SchedulerException {
        //采用spring管理器
        if (springFactoryBean == null) {
            springFactoryBean = new SchedulerFactoryBean();
        }

        return springFactoryBean.getScheduler();
        //return StdSchedulerFactory.getDefaultScheduler();
    }


    public void start() throws SchedulerException {
        try {
            if (!getScheduler().isStarted()) {
                getScheduler().start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public void stop() throws SchedulerException {
        try {
            //true 表示任务返回之后结束
            getScheduler().shutdown(true);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 添加即时重复任务
     *
     * @param jobName
     * @param jobClass
     * @param sce       间隔 秒数
     * @param repeat    重复次数
     * @param startTime
     */
    public void addRepeatJob(String jobName, Class<? extends Job> jobClass, int sce, int repeat, Date startTime, Map<String, Object> map) {
        try {
            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .build();

            JobDataMap dataMap = job.getJobDataMap();
            if (map != null && map.size() > 0) {
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    dataMap.put(entry.getKey(), entry.getValue());
                }
            }
            // 设置属性
            SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule();
            // 重复间隔
            builder.withIntervalInSeconds(sce);
            if (repeat > 0) {
                // 重复次数
                builder.withRepeatCount(repeat);
            }
            // 开始执行


            SimpleTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .startAt(startTime)
                    .withSchedule(builder)
                    .build();

            Scheduler scheduler = getScheduler();
            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 任务立即执行
     *
     * @param jobName
     * @param jobClass
     * @param startTime
     */
    public void addSimpleJob(String jobName, Class<? extends Job> jobClass, Date startTime, Map<String, Object> map) {
        try {
            Scheduler scheduler = getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .build();

            JobDataMap dataMap = job.getJobDataMap();
            if (map != null && map.size() > 0) {
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    dataMap.put(entry.getKey(), entry.getValue());
                }
            }

            // 开始执行
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .startAt(startTime)
                    .build();
            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void addSimpleJob(String jobName, Class<? extends Job> jobClass, Date startTime) {
        try {
            Scheduler scheduler = getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .build();

            // 开始执行
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .startAt(startTime)
                    .build();
            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 任务立即执行
     * 这个加进去的任务并未被执行
     *
     * @param jobName
     * @param jobClass
     */
    public void addSimpleJob(String jobName, Class<? extends Job> jobClass) {
        try {
            //storeDurably 即使没有Trigger关联时，也不需要删除该JobDetail
            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .storeDurably()
                    .build();

            Trigger trigger = TriggerBuilder.newTrigger()
                    .startNow()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .build();

            Scheduler scheduler = getScheduler();
            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 添加cron计划任务
     *
     * @param jobName
     * @param jobClass
     * @param cron
     */
    public void addCronJob(String jobName, Class<? extends Job> jobClass, String cron) {
        try {
            Scheduler scheduler = getScheduler();

            //spring
//            JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
//            jobDetailFactoryBean.setName(jobName);
//            jobDetailFactoryBean.setJobClass(jobClass);
//            jobDetailFactoryBean.setGroup(JOB_GROUP_NAME);
//            jobDetailFactoryBean.getObject();
//
//            JobDetail jobDetail = jobDetailFactoryBean.getObject();
//
//
//            CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
//            cronTriggerFactoryBean.setCronExpression(cron);
//
//            CronTrigger cronTrigger = cronTriggerFactoryBean.getObject();
//
//            SimpleTriggerFactoryBean triggerFactoryBean = new SimpleTriggerFactoryBean();
//            triggerFactoryBean.setJobDetail(jobDetail);
//            triggerFactoryBean.setStartTime(new Date());

            //end

            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .build();


            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .startNow()
                    .withSchedule(cronSchedule(cron))
                    .build();

            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 传入数据
     *
     * @param jobName
     * @param jobClass
     * @param cron
     * @param map
     */
    public void addCronJob(String jobName, Class<? extends Job> jobClass, String cron, Map<String, Object> map) {
        try {
            Scheduler scheduler = getScheduler();
            JobDetail job = JobBuilder.newJob(jobClass)
                    .withIdentity(jobName, JOB_GROUP_NAME)
                    .build();
            JobDataMap dataMap = job.getJobDataMap();
            if (map != null && map.size() > 0) {
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    dataMap.put(entry.getKey(), entry.getValue());
                }
            }

            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(jobName, TRIGGER_GROUP_NAME)
                    .startNow()
                    .withSchedule(cronSchedule(cron))
                    .build();

            if (!scheduler.checkExists(job.getKey())) {
                scheduler.scheduleJob(job, trigger);
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改一个任务 删除久的任务 添加新的任务
     *
     * @param jobName
     * @param cron
     */
    public void modifyCronJob(String jobName, String cron) {
        try {
            Scheduler scheduler = getScheduler();
            TriggerKey key = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(key);
            if (trigger == null) {
                return;
            }
            String oldCron = trigger.getCronExpression();
            if (!oldCron.equalsIgnoreCase(cron)) {
                JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
                JobDetail detail = scheduler.getJobDetail(jobKey);
                Class oldJobClass = detail.getJobClass();
                removeCronJob(jobName);
                addCronJob(jobName, oldJobClass, cron);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 暂停触发器
     *
     * @param jobName
     */
    public void pauseCronTrigger(String jobName) {
        try {
            Scheduler scheduler = getScheduler();
            TriggerKey arg0 = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            scheduler.pauseTrigger(arg0);
            // 停止触发器
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 暂停任务
     *
     * @param jobName
     */
    public void pauseCronJob(String jobName) {
        try {
            Scheduler scheduler = getScheduler();
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            scheduler.pauseJob(jobKey);
            // 停止任务
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 恢复触发器
     *
     * @param jobName
     */
    public void resumeTrigger(String jobName) {
        try {
            TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            getScheduler().resumeTrigger(triggerKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 恢复任务
     *
     * @param jobName
     */
    public void resumeJob(String jobName) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME);
            getScheduler().resumeJob(jobKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 恢复任务
     *
     * @param job
     */
    public void resumeJob(ScheduleJob job) {
        try {
            JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
            getScheduler().resumeJob(jobKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 运行一次任务
     * 运行时任务必须已存在
     *
     * @param jobName
     */
    public void runOne(String jobName) {
        try {
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            getScheduler().triggerJob(jobKey);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取触发器
     *
     * @param jobName
     * @return
     */
    public CronTrigger getCronTrigger(String jobName) {
        try {
            Scheduler scheduler = getScheduler();
            TriggerKey key = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
            return (CronTrigger) scheduler.getTrigger(key);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除一个任务
     *
     * @param jobName
     */
    public void removeCronJob(String jobName) {
        try {
            Scheduler scheduler = getScheduler();
            JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(jobKey);// 删除任务
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取计划中的任务列表
     *
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getCronJobs() throws SchedulerException {

        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
        Set<JobKey> jobKeys = getScheduler().getJobKeys(matcher);
        List<ScheduleJob> schedulers = new ArrayList<>();
        for (JobKey jobKey : jobKeys) {
            List<? extends Trigger> triggers = getScheduler().getTriggersOfJob(
                    jobKey);
            for (Trigger trigger : triggers) {
                ScheduleJob job = new ScheduleJob();
                job.setJobName(jobKey.getName());
                job.setJobGroup(jobKey.getGroup());
                job.setDesc("trigger:" + trigger.getKey());
                Trigger.TriggerState state = getScheduler().getTriggerState(
                        trigger.getKey());
                job.setJobStatus(state.name());

                if (trigger instanceof CronTrigger) {
                    CronTrigger cronTrigger = (CronTrigger) trigger;
                    String cronExpress = cronTrigger.getCronExpression();
                    job.setCronExpression(cronExpress);
                }
                schedulers.add(job);
            }
        }
        return schedulers;
    }

    /**
     * 获取运行中的任务
     *
     * @return
     * @throws SchedulerException
     */
    public List<ScheduleJob> getExecutingJobs() throws SchedulerException {

        List<JobExecutionContext> executionContexts = getScheduler().getCurrentlyExecutingJobs();
        List<ScheduleJob> schedulers = new ArrayList<>(executionContexts.size());
        for (JobExecutionContext context : executionContexts) {
            ScheduleJob job = new ScheduleJob();
            JobDetail detail = context.getJobDetail();
            JobKey jobKey = detail.getKey();
            Trigger trigger = context.getTrigger();
            job.setJobName(jobKey.getName());
            job.setJobGroup(jobKey.getGroup());
            job.setDesc("trigger:" + trigger.getKey());
            Trigger.TriggerState state = getScheduler().getTriggerState(trigger.getKey());
            job.setJobStatus(state.name());
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                String cronExpress = cronTrigger.getCronExpression();
                job.setCronExpression(cronExpress);
            }
            schedulers.add(job);
        }
        return schedulers;
    }

    /**
     * 获取job
     *
     * @param jobName
     * @return
     * @throws SchedulerException
     */
    public ScheduleJob getScheduleJob(String jobName) throws SchedulerException {

        ScheduleJob job = new ScheduleJob();
        Scheduler scheduler = getScheduler();
        JobKey jobKey = new JobKey(jobName, JOB_GROUP_NAME);

        TriggerKey triggerKey = new TriggerKey(jobName, TRIGGER_GROUP_NAME);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        job.setJobName(jobKey.getName());
        job.setJobGroup(jobKey.getGroup());

        Trigger.TriggerState state = scheduler.getTriggerState(triggerKey);

        job.setJobStatus(state.name());
        job.setDesc("trigger:" + triggerKey.getName());
        if (trigger instanceof CronTrigger) {
            job.setCronExpression(((CronTrigger) trigger).getCronExpression());
        }
        return job;

    }

}
